{
 "cells": [
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "任何的序列（或者是可迭代对象）可以通过一个简单的赋值操作来分解为单独的变量。 唯一的要求就是变量的总数和结构必须与序列相吻合。",
   "id": "46826726619f6532"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-03T06:13:38.106828Z",
     "start_time": "2025-06-03T06:13:38.098Z"
    }
   },
   "cell_type": "code",
   "source": [
    "p = (4, 5)\n",
    "x, y = p\n",
    "print(x, y)\n",
    "\n",
    "data = ['ACME', 50, 91.1, (2012, 12, 22)]\n",
    "name,shares,price,date = data\n",
    "print(name,shares,price,date)\n",
    "\n",
    "# _ 可以忽略\n",
    "name,_,price,(y,m,d) = data\n",
    "\n",
    "# 只要可以迭代的就可以分解操作\n",
    "s = 'Hello'\n",
    "a,b,c,d,e = s\n",
    "a,b,c,d,e\n",
    "\n",
    "# 如何突破相同个数的限制，星号表达式\n",
    "def avg(numbers):\n",
    "    return sum(numbers) / len(numbers)\n",
    "\n",
    "def drop_first_last(grades):\n",
    "    first, *middle, last = grades\n",
    "    return avg(middle)\n",
    "\n",
    "avg_val = drop_first_last((0,1,2,3,4,5,5,6,7,8,9,0))\n",
    "avg_val\n",
    "\n",
    "records = [\n",
    "    ('foo', 1, 2),\n",
    "    ('bar', 'hello'),\n",
    "    ('foo', 3, 4),\n",
    "]\n",
    "def do_foo(x, y):\n",
    "    print('foo', x, y)\n",
    "\n",
    "def do_bar(s):\n",
    "    print('bar', s)\n",
    "\n",
    "for tag, *args in records:\n",
    "    if tag == 'foo':\n",
    "        do_foo(*args)\n",
    "    elif tag == 'bar':\n",
    "        do_bar(*args)\n",
    "\n",
    "line = 'nobody:*:-2:-2:Unprivileged User:/var/empty:/usr/bin/false'\n",
    "uname,*fields,homedir,sh = line.split(':')\n",
    "(uname, homedir, sh)\n",
    "\n",
    "# *可以结合_ 来丢弃不要的数据\n",
    "records = ['ACME', 50, 91.1, (2012, 12, 22)]\n",
    "name, *_, (*_, year) = records\n",
    "name, year\n",
    "\n",
    "# 递归求和\n",
    "def sum_recursion(nums):\n",
    "    first, *rest = nums\n",
    "    return first + sum_recursion(rest) if rest else first\n",
    "\n",
    "sum_recursion([1,2,3,4,5,6,7,8,9,0])\n"
   ],
   "id": "d12dd07ffc4a038f",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "4 5\n",
      "ACME 50 91.1 (2012, 12, 22)\n",
      "foo 1 2\n",
      "bar hello\n",
      "foo 3 4\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "45"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 16
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": [
    "# 保留最后N个元素\n",
    "使用collection.deque，保留最后命中的5行。"
   ],
   "id": "5f35cddeb0911f82"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-03T06:33:49.239255Z",
     "start_time": "2025-06-03T06:33:49.235270Z"
    }
   },
   "cell_type": "code",
   "source": [
    "from collections import deque\n",
    "def search(lines, pattern, history = 5):\n",
    "    previous_lines = deque(maxlen=5)\n",
    "    pattern_lower = pattern.lower()\n",
    "    for line in lines:\n",
    "        previous_lines.append(line)\n",
    "        if pattern in line.lower():\n",
    "            yield previous_lines\n",
    "\n",
    "with open(\"./some.txt\", 'r', encoding='utf-8') as f:\n",
    "    for deq in search(f, 'python', 5):\n",
    "        for line in deq:\n",
    "            print(line, end='')\n",
    "        print(\" ----------------------- \")"
   ],
   "id": "496ef5327e96b153",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Python 3.13 带来了许多新特性，以下是一些主要的方面\n",
      " ----------------------- \n",
      "Python 3.13 带来了许多新特性，以下是一些主要的方面\n",
      "：\n",
      "交互式解释器改进 ：默认使用新的交互式 shell，基于 PyPy 项目代码，提供更好的错误消息提示，支持自动补全、历史记录、语法高亮等功能，提升了开发者在快速测试和调试时的效率。\n",
      "自由线程模式（PEP 703） ：实验性地支持在禁用全局解释器锁（GIL）的情况下运行，也称为自由线程模式。这样可以通过在可用的 CPU 核心上并行运行线程来充分利用处理能力，对于多线程计算密集型任务性能提升有很大帮助，但目前该功能处于实验阶段，官方建议仅在测试环境中使用。\n",
      "即时编译器（PEP 744） ：引入了实验性的 Just - In - Time（JIT）编译器，默认禁用。启用后可将 Python 代码编译为机器代码，减少解释器开销，尤其在循环和函数调用频繁的场景中性能提升明显，不过目前也处于实验阶段。\n",
      " ----------------------- \n",
      "模块优化 ：collections.Counter 在处理大量数据时性能得到优化；re 模块在正则表达式匹配，尤其是处理复杂模式时速度显著提升；json 模块增加了对 datetime 对象的直接序列化支持等。\n",
      "移除模块 ：按照 PEP 594，移除了如 aifc、audioop、chunk 等多个已被标记为弃用的模块。\n",
      "类型注解支持增强 ：类型形参现在可以支持设置默认值，还新增了 ReadOnly 用于标记 TypedDict 项为只读，TypeIs 用于类型检查器类型收窄等，为类型注解提供了更多灵活性。\n",
      "平台支持扩展 ：正式将 iOS 和 Android 平台提升为官方支持的平台，支持级别为 3 级，为移动应用开发者带来了便利。同时，WASI 成为 2 级支持平台，而 Emscripten 不再是官方支持平台（但 Pyodide 继续支持 Emscripten）。\n",
      "其他变化 ：类新增了 __static_attributes__ 属性用于存储从类主体中任何函数通过 self.X 访问的属性名称，编译器还会在类上创建 __firstlineno__ 属性包含类定义第一行的行号；新增了 PythonFinalizationError 异常，当操作在终结过程中被阻塞时抛出等。\n",
      " ----------------------- \n"
     ]
    }
   ],
   "execution_count": 41
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-03T06:38:38.749269Z",
     "start_time": "2025-06-03T06:38:38.744830Z"
    }
   },
   "cell_type": "code",
   "source": [
    "# deque 使用\n",
    "q = deque()\n",
    "q.append(1)\n",
    "q.append(2)\n",
    "q.append(3)\n",
    "q\n",
    "q.appendleft(4)\n",
    "q\n",
    "q.pop()\n",
    "q\n",
    "q.popleft()\n",
    "q"
   ],
   "id": "d3e9881f1c6e6fa0",
   "outputs": [
    {
     "data": {
      "text/plain": [
       "deque([1, 2])"
      ]
     },
     "execution_count": 45,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 45
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": [
    "# 先级队列（堆队列）\n",
    "heapq模块\n",
    "查找最大或最小的N个元素"
   ],
   "id": "d892c2b7709f900b"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-03T06:45:31.340239Z",
     "start_time": "2025-06-03T06:45:31.333832Z"
    }
   },
   "cell_type": "code",
   "source": [
    "# 使用heapq的来那个个函数：nlargest和nsmallest\n",
    "import heapq\n",
    "nums = [1, 8, 2, 23, 7, -4, 18, 23, 42, 37, 2]\n",
    "print(heapq.nlargest(3, nums))\n",
    "print(heapq.nsmallest(3, nums))\n",
    "\n",
    "# 两个函数都能接受一个关键字参数，用于更复杂的数据结构中：\n",
    "portfolio = [\n",
    "    {'name': 'IBM', 'shares': 100, 'price': 91.1},\n",
    "    {'name': 'AAPL', 'shares': 50, 'price': 543.22},\n",
    "    {'name': 'FB', 'shares': 200, 'price': 21.09},\n",
    "    {'name': 'HPQ', 'shares': 35, 'price': 31.75},\n",
    "    {'name': 'YHOO', 'shares': 45, 'price': 16.35},\n",
    "    {'name': 'ACME', 'shares': 75, 'price': 115.65}\n",
    "]\n",
    "cheap = heapq.nsmallest(3, portfolio, key=lambda item: item['price'])\n",
    "expensive = heapq.nlargest(3, portfolio, key=lambda item: item['price'])\n",
    "cheap, expensive"
   ],
   "id": "8f7b71006687dec3",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[42, 37, 23]\n",
      "[-4, 1, 2]\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "([{'name': 'YHOO', 'shares': 45, 'price': 16.35},\n",
       "  {'name': 'FB', 'shares': 200, 'price': 21.09},\n",
       "  {'name': 'HPQ', 'shares': 35, 'price': 31.75}],\n",
       " [{'name': 'AAPL', 'shares': 50, 'price': 543.22},\n",
       "  {'name': 'ACME', 'shares': 75, 'price': 115.65},\n",
       "  {'name': 'IBM', 'shares': 100, 'price': 91.1}])"
      ]
     },
     "execution_count": 47,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 47
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-03T07:23:49.575995Z",
     "start_time": "2025-06-03T07:23:49.568922Z"
    }
   },
   "cell_type": "code",
   "source": [
    "# 常用方法\n",
    "import heapq\n",
    "data = [3, 1, 4, 1, 5, 9, 2, 6]\n",
    "heapq.heapify(data)   # 将原列表转成堆   注意：堆在列表中的存储形式并不一定完全有序，但满足堆性质。\n",
    "heapq.heappush(data, 0)\n",
    "print(data)\n",
    "print(heapq.heappop(data))\n",
    "data\n",
    "heapq.heapify(data)\n",
    "\n",
    "# 最大堆   heapq只有最小堆，要用最大堆只能加负值模拟\n",
    "# 如果是复杂对象，可以实现__lt__ 小于比较方法，或者使用元组包裹，元组按顺序比较元组内每个元素大小\n",
    "# 必须是可比较的对象，但也可以规避，比如套个元组，前面的元素不会重复，就不会计算到不可比较的元素。\n",
    "data = [3, 1, 4, 1, 5, 9, 2, 6]\n",
    "max_heap = [-x for x in data]\n",
    "max_heap\n",
    "heapq.heapify(max_heap)\n",
    "-heapq.heappop(max_heap)\n",
    "\n",
    "# 优先级队列实现\n",
    "class PriorityQueue:\n",
    "    def __init__(self):\n",
    "        self._queue = []\n",
    "        self._index = 0\n",
    "\n",
    "    def push(self, item, priority):\n",
    "        heapq.heappush(self._queue, (-priority, self._index, item))\n",
    "        self._index += 1\n",
    "\n",
    "    def pop(self):\n",
    "        return heapq.heappop(self._queue)[-1]\n",
    "\n",
    "class Item:\n",
    "    def __init__(self, name):\n",
    "        self.name = name\n",
    "    def __repr__(self):\n",
    "        return f'Item({self.name})'\n",
    "\n",
    "q = PriorityQueue()\n",
    "q.push(Item('foo'), 1)\n",
    "q.push(Item('bar'), 5)\n",
    "q.push(Item('spam'), 4)\n",
    "q.push(Item('grok'), 1)  # index 是为了，如果是两个相同优先级的元素，按插入顺序输出\n",
    "q.pop()\n",
    "q.pop()\n",
    "q.pop()\n",
    "q.pop()"
   ],
   "id": "7bd29e89d95e60d2",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[0, 1, 2, 1, 5, 9, 4, 6, 3]\n",
      "0\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "Item(grok)"
      ]
     },
     "execution_count": 58,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 58
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": [
    "# 字典中的键映射多个值\n",
    "使用defaultdict，可以在创建dict的时候，选择val类型为list，set等"
   ],
   "id": "67e1c509d328c69e"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-03T07:39:51.817995Z",
     "start_time": "2025-06-03T07:39:40.609155Z"
    }
   },
   "cell_type": "code",
   "source": [
    "from collections import defaultdict\n",
    "d = defaultdict(list)\n",
    "d['a'].append(1)\n",
    "d['a'].append(2)\n",
    "d['b'].append(4)\n",
    "d\n",
    "\n",
    "d = defaultdict(set)\n",
    "d['a'].add(1)\n",
    "d['a'].add(2)\n",
    "d['b'].add(4)\n",
    "d"
   ],
   "id": "62411b515d1d309a",
   "outputs": [
    {
     "data": {
      "text/plain": [
       "defaultdict(set, {'a': {1, 2}, 'b': {4}})"
      ]
     },
     "execution_count": 63,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 63
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": [
    "# 字典排序\n",
    "使用OrderedDict"
   ],
   "id": "b2d2f17cfb319748"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-03T07:43:37.536007Z",
     "start_time": "2025-06-03T07:43:37.531563Z"
    }
   },
   "cell_type": "code",
   "source": [
    "from collections import OrderedDict\n",
    "d = OrderedDict()\n",
    "d['foo'] = 1\n",
    "d['bar'] = 2\n",
    "d['spam'] = 3\n",
    "d['grok'] = 4\n",
    "for key in d:\n",
    "    print(key, d[key])\n",
    "\n",
    "# 输出json时，可以通过OrderedDict控制顺序\n",
    "import json\n",
    "json.dumps(d)"
   ],
   "id": "59cf9a32d59fa6c9",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "foo 1\n",
      "bar 2\n",
      "spam 3\n",
      "grok 4\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'{\"foo\": 1, \"bar\": 2, \"spam\": 3, \"grok\": 4}'"
      ]
     },
     "execution_count": 66,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 66
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": [
    "# 字典的运算\n",
    "使用zip()\n",
    "+ 输入 ：多个可迭代对象（至少两个）。\n",
    "+ 输出 ：一个生成元组的迭代器，每个元组包含输入序列中相同索引的元素。\n",
    "+ 长度规则 ：若输入序列长度不同，结果以 最短序列 的长度为准（多余元素被忽略）\n",
    "可以用来：\n",
    "转成元组\n",
    "```\n",
    "names = [\"Alice\", \"Bob\", \"Charlie\"]\n",
    "scores = [85, 92, 78]\n",
    "\n",
    "zipped = zip(names, scores)\n",
    "print(list(zipped))  # 输出: [('Alice', 85), ('Bob', 92), ('Charlie', 78)]\n",
    "```\n",
    "并行迭代多个序列\n",
    "```\n",
    "for name, score in zip(names, scores):\n",
    "    print(f\"{name}: {score}分\")\n",
    "```\n",
    "解压（逆向操作）\n",
    "```\n",
    "data = [('Alice', 85), ('Bob', 92), ('Charlie', 78)]\n",
    "unzipped_names, unzipped_scores = zip(*data)\n",
    "print(unzipped_names)   # 输出: ('Alice', 'Bob', 'Charlie')\n",
    "print(unzipped_scores)  # 输出: (85, 92, 78)\n",
    "```\n",
    "矩阵转置 ：将二维列表的行列互换：\n",
    "```\n",
    "matrix = [[1, 2, 3], [4, 5, 6]]\n",
    "transposed = list(zip(*matrix))  # 输出: [(1,4), (2,5), (3,6)]\n",
    "```\n",
    "字典构造 ：快速创建字典:\n",
    "```\n",
    "keys = [\"a\", \"b\", \"c\"]\n",
    "values = [1, 2, 3]\n",
    "dict_from_zip = dict(zip(keys, values))  # 输出: {'a': 1, 'b': 2, 'c': 3}\n",
    "```"
   ],
   "id": "70a6da5ed870b99c"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-03T07:54:07.251145Z",
     "start_time": "2025-06-03T07:54:07.246958Z"
    }
   },
   "cell_type": "code",
   "source": [
    "# 字典中取最大最小值，排序\n",
    "prices = {\n",
    "    'ACME': 45.23,\n",
    "    'AAPL': 612.78,\n",
    "    'IBM': 205.55,\n",
    "    'HPQ': 37.20,\n",
    "    'FB': 10.75,\n",
    "    'ZB': 10.75\n",
    "}\n",
    "\n",
    "min_price = min(zip(prices.values(), prices.keys())) # 其实比较的是元组\n",
    "min_price\n",
    "\n",
    "max_price = max(zip(prices.values(), prices.keys()))\n",
    "max_price\n",
    "\n",
    "prices_sorted = sorted(zip(prices.values(), prices.keys()))\n",
    "prices_sorted\n",
    "\n",
    "# 注意：zip函数创建的对象只能使用一次，因为创建出来的是个迭代器、"
   ],
   "id": "6cfb7b2b93c83fef",
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[(10.75, 'FB'),\n",
       " (10.75, 'ZB'),\n",
       " (37.2, 'HPQ'),\n",
       " (45.23, 'ACME'),\n",
       " (205.55, 'IBM'),\n",
       " (612.78, 'AAPL')]"
      ]
     },
     "execution_count": 72,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 72
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "# 查找两字典的相同点",
   "id": "4dfbd2e30e1e6307"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-03T09:58:35.452003Z",
     "start_time": "2025-06-03T09:58:35.447446Z"
    }
   },
   "cell_type": "code",
   "source": [
    "a = {\n",
    "    'x' : 1,\n",
    "    'y' : 2,\n",
    "    'z' : 3\n",
    "}\n",
    "\n",
    "b = {\n",
    "    'w' : 10,\n",
    "    'x' : 11,\n",
    "    'y' : 2\n",
    "}\n",
    "a.keys()\n",
    "\n",
    "a.keys() & b.keys()\n",
    "a.keys() - b.keys() # z\n",
    "a.items() & b.items() # (y,2)\n",
    "# a.values() & b.values()   会报错，values返回的视图不支持集合操作\n",
    "# list(a.values()) & list(b.values())  会报错，list不支持集合操作\n",
    "set(a.values()) & set(b.values())\n",
    "\n",
    "# 过滤字典元素\n",
    "# {x : 2*x for x in range(5)}\n",
    "c = {key:a[key] for key in a.keys() - {'z', 'w'}}\n",
    "c"
   ],
   "id": "f0a8edf4175e2f20",
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'x': 1, 'y': 2}"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 18
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "# 删除序列相同元素并保持顺序",
   "id": "55bb630bfc1af26d"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-04T09:57:08.949211Z",
     "start_time": "2025-06-04T09:57:08.944117Z"
    }
   },
   "cell_type": "code",
   "source": [
    "def dedupe(items):\n",
    "    seen = set()\n",
    "    for item in items:\n",
    "        if item not in seen:\n",
    "            yield item\n",
    "            seen.add(item)\n",
    "\n",
    "a = [1, 5, 2, 1, 9, 1, 5, 10]\n",
    "\n",
    "set(a) # 这种方式不保证顺序\n",
    "list(dedupe(a))\n",
    "\n",
    "def dedupe(items, key=None):\n",
    "    seen = set()\n",
    "    for item in items:\n",
    "        val = item if key is None else key(item)\n",
    "        if val not in seen:\n",
    "            yield item\n",
    "            seen.add(val)\n",
    "\n",
    "a=[{'x':1,'y':2},{'x':1,'y':3},{'x':1,'y':2},{'x':2,'y':4}]\n",
    "list(dedupe(a, key=lambda x: x['x']))"
   ],
   "id": "648277c43eefa23",
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[{'x': 1, 'y': 2}, {'x': 2, 'y': 4}]"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 12
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "# 命名切片",
   "id": "50f41e2e76027cb0"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-04T10:16:54.204250Z",
     "start_time": "2025-06-04T10:16:54.200341Z"
    }
   },
   "cell_type": "code",
   "source": [
    "######    0123456789012345678901234567890123456789012345678901234567890'\n",
    "record = '....................100 .......513.25 ..........'\n",
    "cost = int(record[20:23]) * float(record[31:37])\n",
    "cost\n",
    "# 与其那样写，为什么不像这样命名切片呢：\n",
    "SHARES = slice(20, 23)\n",
    "PRICE = slice(31, 37)\n",
    "int(record[SHARES]) * float(record[PRICE])\n",
    "\n",
    "# 可以通过调用切片的 indices(size) 方法将它映射到一个已知大小的序列上。 这个方法返回一个三元组 (start, stop, step) ，所有的值都会被缩小，直到适合这个已知序列的边界为止。  还能处理负参数，转为正参数，就是一个规则化，确定化。\n",
    "a = slice(5, 50, 2)\n",
    "s = 'HelloWorld'\n",
    "a.indices(len(s)) # (5, 10, 2)\n",
    "for i in range(*a.indices(len(s))):  # * 可以解包迭代对象为位置参数\n",
    "     print(s[i])"
   ],
   "id": "c2484beef18982f4",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "W\n",
      "r\n",
      "d\n"
     ]
    }
   ],
   "execution_count": 20
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "# 序列中出现次数最多的元素",
   "id": "dc7ff4e3581a158b"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-06T09:39:56.093063Z",
     "start_time": "2025-06-06T09:39:56.087746Z"
    }
   },
   "cell_type": "code",
   "source": [
    "from collections import Counter\n",
    "words = [\n",
    "    'look', 'into', 'my', 'eyes', 'look', 'into', 'my', 'eyes',\n",
    "    'the', 'eyes', 'the', 'eyes', 'the', 'eyes', 'not', 'around', 'the',\n",
    "    'eyes', \"don't\", 'look', 'around', 'the', 'eyes', 'look', 'into',\n",
    "    'my', 'eyes', \"you're\", 'under'\n",
    "]\n",
    "word_counts = Counter(words)\n",
    "word_counts.most_common(3)\n",
    "word_counts['eyes']\n",
    "word_counts['eyes'] += 1\n",
    "word_counts['eyes']\n",
    "\n",
    "morewords = ['why','are','you','not','looking','eyes','in','my','eyes']\n",
    "word_counts.update(morewords)\n",
    "word_counts\n",
    "\n",
    "a = Counter(words)\n",
    "b = Counter(morewords)\n",
    "c = a+b\n",
    "c = a-b\n",
    "c"
   ],
   "id": "26ef82873487b662",
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Counter({'eyes': 6,\n",
       "         'the': 5,\n",
       "         'look': 4,\n",
       "         'into': 3,\n",
       "         'my': 2,\n",
       "         'around': 2,\n",
       "         \"don't\": 1,\n",
       "         \"you're\": 1,\n",
       "         'under': 1})"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 9
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "# 通过某个关键字排序一个字典列表",
   "id": "2be421894041a422"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-06T09:43:34.500935Z",
     "start_time": "2025-06-06T09:43:34.495410Z"
    }
   },
   "cell_type": "code",
   "source": [
    "rows = [\n",
    "    {'fname': 'Brian', 'lname': 'Jones', 'uid': 1003},\n",
    "    {'fname': 'David', 'lname': 'Beazley', 'uid': 1002},\n",
    "    {'fname': 'John', 'lname': 'Cleese', 'uid': 1001},\n",
    "    {'fname': 'Big', 'lname': 'Jones', 'uid': 1004}\n",
    "]\n",
    "\n",
    "from operator import itemgetter\n",
    "rows_by_fname = sorted(rows, key=itemgetter('fname'))\n",
    "rows_by_lname = sorted(rows, key=itemgetter('lname'))\n",
    "print(rows_by_fname)\n",
    "print(rows_by_lname)\n",
    "\n",
    "rows_by_lfname = sorted(rows, key=itemgetter('lname', 'fname'))\n",
    "rows_by_lfname\n",
    "\n",
    "# 等价于，但是itemgetter性能更高\n",
    "rows_by_fname = sorted(rows, key=lambda r: r['fname'])\n",
    "rows_by_lfname = sorted(rows, key=lambda r: (r['lname'],r['fname']))\n",
    "rows_by_fname\n",
    "\n",
    "min(rows, key=itemgetter('uid'))\n",
    "max(rows, key=itemgetter('uid'))"
   ],
   "id": "e8885408259f3a0f",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[{'fname': 'Big', 'lname': 'Jones', 'uid': 1004}, {'fname': 'Brian', 'lname': 'Jones', 'uid': 1003}, {'fname': 'David', 'lname': 'Beazley', 'uid': 1002}, {'fname': 'John', 'lname': 'Cleese', 'uid': 1001}]\n",
      "[{'fname': 'David', 'lname': 'Beazley', 'uid': 1002}, {'fname': 'John', 'lname': 'Cleese', 'uid': 1001}, {'fname': 'Brian', 'lname': 'Jones', 'uid': 1003}, {'fname': 'Big', 'lname': 'Jones', 'uid': 1004}]\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "{'fname': 'Big', 'lname': 'Jones', 'uid': 1004}"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 15
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "# 排序不支持原生比较的对象",
   "id": "dab0ad71b62e19a0"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-06T09:53:28.725560Z",
     "start_time": "2025-06-06T09:53:28.720991Z"
    }
   },
   "cell_type": "code",
   "source": [
    "class User:\n",
    "    def __init__(self, user_id):\n",
    "        self.user_id = user_id\n",
    "\n",
    "    def __repr__(self):\n",
    "        return 'User({})'.format(self.user_id)\n",
    "\n",
    "users = [User(23), User(3), User(99)]\n",
    "sorted(users, key=lambda u: u.user_id)\n",
    "sorted(users, key=lambda u: u.user_id, reverse=True)\n",
    "\n",
    "from operator import attrgetter\n",
    "sorted(users, key=attrgetter('user_id'), reverse=True)\n",
    "\n",
    "min(users, key=attrgetter('user_id'))\n",
    "max(users, key=attrgetter('user_id'))"
   ],
   "id": "de92fce9d68fffc0",
   "outputs": [
    {
     "data": {
      "text/plain": [
       "User(99)"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 20
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": [
    "# 通过某个字段将记录分组\n",
    "一个非常重要的准备步骤是要根据指定的字段将数据排序。 因为 groupby() 仅仅检查连续的元素，如果事先并没有排序完成的话，分组函数将得不到想要的结果。"
   ],
   "id": "74cc88a57f71e943"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-15T02:41:12.111535Z",
     "start_time": "2025-06-15T02:41:12.106631Z"
    }
   },
   "cell_type": "code",
   "source": [
    "rows = [\n",
    "    {'address': '5412 N CLARK', 'date': '07/01/2012'},\n",
    "    {'address': '5148 N CLARK', 'date': '07/04/2012'},\n",
    "    {'address': '5800 E 58TH', 'date': '07/02/2012'},\n",
    "    {'address': '2122 N CLARK', 'date': '07/03/2012'},\n",
    "    {'address': '5645 N RAVENSWOOD', 'date': '07/02/2012'},\n",
    "    {'address': '1060 W ADDISON', 'date': '07/02/2012'},\n",
    "    {'address': '4801 N BROADWAY', 'date': '07/01/2012'},\n",
    "    {'address': '1039 W GRANVILLE', 'date': '07/04/2012'},\n",
    "]\n",
    "\n",
    "from operator import itemgetter\n",
    "from itertools import groupby\n",
    "\n",
    "rows.sort(key=itemgetter('date'))\n",
    "for date,items in groupby(rows, key=itemgetter('date')):\n",
    "    print(date)\n",
    "    for item in items:\n",
    "        print(' ', item)\n"
   ],
   "id": "35edd9a6924360a7",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "07/01/2012\n",
      "  {'address': '5412 N CLARK', 'date': '07/01/2012'}\n",
      "  {'address': '4801 N BROADWAY', 'date': '07/01/2012'}\n",
      "07/02/2012\n",
      "  {'address': '5800 E 58TH', 'date': '07/02/2012'}\n",
      "  {'address': '5645 N RAVENSWOOD', 'date': '07/02/2012'}\n",
      "  {'address': '1060 W ADDISON', 'date': '07/02/2012'}\n",
      "07/03/2012\n",
      "  {'address': '2122 N CLARK', 'date': '07/03/2012'}\n",
      "07/04/2012\n",
      "  {'address': '5148 N CLARK', 'date': '07/04/2012'}\n",
      "  {'address': '1039 W GRANVILLE', 'date': '07/04/2012'}\n"
     ]
    }
   ],
   "execution_count": 1
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "# 过滤序列元素",
   "id": "b2aaace1f061d67e"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-15T02:53:32.154654Z",
     "start_time": "2025-06-15T02:53:32.147760Z"
    }
   },
   "cell_type": "code",
   "source": [
    "mylist = [1, 4, -5, 10, -7, 2, 3, -1]\n",
    "[n for n in mylist if n > 0]\n",
    "[n for n in mylist if n < 0]\n",
    "\n",
    "pos = (n for n in mylist if n >0)\n",
    "for x in pos:\n",
    "    print(x)\n",
    "\n",
    "# 使用函数过滤，需要配合filter内置方法\n",
    "values = ['1', '2', '-3', '-', '4', 'N/A', '5']\n",
    "def is_int(val):\n",
    "    try:\n",
    "        x = int(val)\n",
    "        return True\n",
    "    except ValueError:\n",
    "        return False\n",
    "\n",
    "ivals = list(filter(is_int, values))\n",
    "ivals\n",
    "\n",
    "# 直接转换数据\n",
    "mylist = [1, 4, -5, 10, -7, 2, 3, -1]\n",
    "import math\n",
    "[math.sqrt(n) for n in mylist if n >0]\n",
    "pos = (math.sqrt(n) for n in mylist if n >0)\n",
    "for x in pos:\n",
    "    print(x)\n",
    "\n",
    "clip_neg = [n if n > 0 else 0 for n in mylist]\n",
    "clip_neg\n",
    "\n",
    "addresses = [\n",
    "    '5412 N CLARK',\n",
    "    '5148 N CLARK',\n",
    "    '5800 E 58TH',\n",
    "    '2122 N CLARK',\n",
    "    '5645 N RAVENSWOOD',\n",
    "    '1060 W ADDISON',\n",
    "    '4801 N BROADWAY',\n",
    "    '1039 W GRANVILLE',\n",
    "]\n",
    "counts = [ 0, 3, 10, 4, 1, 7, 6, 1]\n",
    "more5 = [n > 5 for n in counts]\n",
    "from itertools import compress\n",
    "list(compress(addresses, more5))\n"
   ],
   "id": "69d7685fa3eb4c34",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "4\n",
      "10\n",
      "2\n",
      "3\n",
      "1.0\n",
      "2.0\n",
      "3.1622776601683795\n",
      "1.4142135623730951\n",
      "1.7320508075688772\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "['5800 E 58TH', '1060 W ADDISON', '4801 N BROADWAY']"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 18
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "# 从字典中提取子集",
   "id": "d37af60ef3e49216"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-15T02:59:11.839876Z",
     "start_time": "2025-06-15T02:59:11.835142Z"
    }
   },
   "cell_type": "code",
   "source": [
    "prices = {\n",
    "    'ACME': 45.23,\n",
    "    'AAPL': 612.78,\n",
    "    'IBM': 205.55,\n",
    "    'HPQ': 37.20,\n",
    "    'FB': 10.75\n",
    "}\n",
    "p1 = {key : value for key, value in prices.items() if value > 200}\n",
    "p1\n",
    "tech_names = {'AAPL', 'IBM', 'HPQ', 'MSFT'}\n",
    "p2 = {key:value for key, value in prices.items() if key in tech_names}\n",
    "p2\n",
    "# 大多数情况下字典推导能做到的，通过创建一个元组序列然后把它传给 dict() 函数也能实现。\n",
    "p1 = dict((key, value) for key, value in prices.items() if key in tech_names)\n",
    "p1\n",
    "# 取交集 但是慢，最快是推导表达式\n",
    "p2 = {key:prices[key] for key in prices.keys() & tech_names}\n",
    "p2"
   ],
   "id": "94b1b7f7f99ed4c3",
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'HPQ': 37.2, 'AAPL': 612.78, 'IBM': 205.55}"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 23
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "# 映射名称到序列元素",
   "id": "8dc0f4dfdb535c9d"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-15T03:06:10.646901Z",
     "start_time": "2025-06-15T03:06:10.642679Z"
    }
   },
   "cell_type": "code",
   "source": [
    "from collections import namedtuple\n",
    "Subscriber = namedtuple(\"Subscriber\", ['addr','joined'])\n",
    "sub = Subscriber('jonesy@example.com', '2012-10-19')\n",
    "sub\n",
    "len(sub)\n",
    "addr, joined = sub\n",
    "addr,joined\n",
    "\n",
    "# 命名元组是不可修改的，但如果真需要改变，可以使用命名元组的_replace方法，生成一个新的命名元组\n",
    "# sub.addr = 1 报错\n",
    "sub\n",
    "sub = sub._replace(addr='1')\n",
    "sub\n",
    "\n",
    "# 可以先创建一个带有缺省值的元组，再通过_replace方法修改出很多衍生元组"
   ],
   "id": "12b6b27b0ede599",
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Subscriber(addr='1', joined='2012-10-19')"
      ]
     },
     "execution_count": 29,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 29
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "# 转换并同时计算数据",
   "id": "e50978802634c3d1"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-15T03:13:39.851907Z",
     "start_time": "2025-06-15T03:13:39.847650Z"
    }
   },
   "cell_type": "code",
   "source": [
    "# 生成器直接作为参数传给函数。\n",
    "nums = [1,2,3,4,5]\n",
    "s = sum(x * x for x in nums)\n",
    "s\n",
    "s = ('ACME', 50, 123.45)\n",
    "print(','.join(str(x) for x in s))\n",
    "','.join(str(x) for x in s)"
   ],
   "id": "bae1d406eb402ea7",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "ACME,50,123.45\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'ACME,50,123.45'"
      ]
     },
     "execution_count": 34,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 34
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "# 合并多个字典或映射",
   "id": "f8b08a4bf4cf4b67"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-15T03:24:16.113429Z",
     "start_time": "2025-06-15T03:24:16.108176Z"
    }
   },
   "cell_type": "code",
   "source": [
    "a = {'x': 1, 'z': 3 }\n",
    "b = {'y': 2, 'z': 4 }\n",
    "from collections import ChainMap\n",
    "c = ChainMap(a, b)\n",
    "c['x']\n",
    "c['y']\n",
    "c['z'] # 如果出现重复键，那么第一次出现的映射值会被返回。 因此，例子程序中的 c['z'] 总是会返回字典 a 中对应的值，而不是 b 中对应的值。\n",
    "# 一个 ChainMap 接受多个字典并将它们在逻辑上变为一个字典。 然后，这些字典并不是真的合并在一起了， ChainMap 类只是在内部创建了一个容纳这些字典的列表 并重新定义了一些常见的字典操作来遍历这个列表。大部分字典操作都是可以正常使用的\n",
    "len(c)\n",
    "list(c.keys())\n",
    "list(c.values())\n",
    "# 对于字典的更新或删除操作总是影响的是列表中第一个字典。\n",
    "c['z'] = 10\n",
    "c['w'] = 40\n",
    "a\n",
    "b\n",
    "# ChainMap 对于编程语言中的作用范围变量（比如 globals , locals 等）是非常有用的。 事实上，有一些方法可以使它变得简单：\n",
    "values = ChainMap()\n",
    "values['x'] = 1\n",
    "values = values.new_child()\n",
    "values['x'] = 2\n",
    "values = values.new_child()\n",
    "values['x'] = 3\n",
    "values\n",
    "values['x']\n",
    "values = values.parents\n",
    "values['x']\n",
    "values = values.parents\n",
    "values['x']\n",
    "values\n",
    "\n",
    "# 也可以使用update将两个字典合并\n",
    "a = {'x': 1, 'z': 3 }\n",
    "b = {'y': 2, 'z': 4 }\n",
    "merged = dict(b)\n",
    "merged.update(a)\n",
    "merged"
   ],
   "id": "bdb51f8f47a6d431",
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'y': 2, 'z': 3, 'x': 1}"
      ]
     },
     "execution_count": 50,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 50
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
